/**
 * Created by IntelliJ IDEA.
 * User: Administrator
 * Date: Dec 31, 2009
 * Time: 11:01:36 AM
 * To change this template use File | Settings | File Templates.
 */
import dk.brics.automaton.Automaton;
import java.io.*;
import java.net.URL;
import java.util.*;
import org.jdom.*;

// Referenced classes of package dk.brics.jwig.analysis.summarygraph:
//            Template, Node, TemplateEdge, StringEdge,
//            Location

public class Graph
{

    public Graph()
    {
        nodes = new HashMap();
        roots = new HashMap();
        tgaps_open = new HashSet();
        tgaps_closed = new HashSet();
        agaps_open = new HashSet();
        agaps_closed = new HashSet();
    }

    public Graph(Document document)
        throws IOException, OptionalDataException, ClassCastException, ClassNotFoundException, InvalidClassException
    {
        this();
        init(document, null);
    }

    public Graph(Document document, HashMap hashmap)
        throws IOException, OptionalDataException, ClassCastException, ClassNotFoundException, InvalidClassException
    {
        this();
        init(document, hashmap);
    }

    private void init(Document document, HashMap hashmap)
        throws IOException, OptionalDataException, ClassCastException, ClassNotFoundException, InvalidClassException
    {
        Element element = document.getRootElement();
        Namespace namespace = Namespace.getNamespace(sg_namespace);
        Node node3;
        for(Iterator iterator = element.getChildren("node", namespace).iterator(); iterator.hasNext(); addNode(node3))
        {
            Element element1 = (Element)iterator.next();
            ArrayList arraylist = new ArrayList();
            Iterator iterator6 = element1.getContent().iterator();
            do
            {
                if(!iterator6.hasNext())
                    break;
                Object obj = iterator6.next();
                if(obj instanceof Text)
                    arraylist.add((Text)((Text)obj).clone());
                else
                if(obj instanceof Element)
                    arraylist.add((Element)((Element)obj).clone());
                else
                if(obj instanceof Comment)
                    arraylist.add((Comment)((Comment)obj).clone());
                else
                if(obj instanceof ProcessingInstruction)
                    arraylist.add((ProcessingInstruction)((ProcessingInstruction)obj).clone());
                else
                if(obj instanceof CDATA)
                    arraylist.add((CDATA)((CDATA)obj).clone());
                else
                if(obj instanceof EntityRef)
                    arraylist.add((EntityRef)((EntityRef)obj).clone());
            } while(true);
            Template template = new Template(arraylist);
            String s4 = element1.getAttributeValue("origin");
            if(s4 == null)
                s4 = "?";
            node3 = new Node(element1.getAttributeValue("id"), template, s4);
        }

        Element element2;
        for(Iterator iterator1 = element.getChildren("root", namespace).iterator(); iterator1.hasNext(); addRoot(lookupNode(element2.getAttributeValue("node"))))
            element2 = (Element)iterator1.next();

        Node node;
        String s;
        Node node2;
        HashSet hashset;
        for(Iterator iterator2 = element.getChildren("templateedge", namespace).iterator(); iterator2.hasNext(); node.addTemplateEdge(new TemplateEdge(node2, s, hashset)))
        {
            Element element3 = (Element)iterator2.next();
            node = lookupNode(element3.getAttributeValue("src"));
            s = element3.getAttributeValue("gap");
            node2 = lookupNode(element3.getAttributeValue("dest"));
            hashset = new HashSet();
            Element element8;
            for(Iterator iterator8 = element3.getChildren("origin", namespace).iterator(); iterator8.hasNext(); hashset.add(element8.getText()))
                element8 = (Element)iterator8.next();

            if(hashset.isEmpty())
                hashset.add("?");
        }

        HashMap hashmap1 = new HashMap();
        Iterator iterator3 = element.getChildren("regdef", namespace).iterator();
        do
        {
            if(!iterator3.hasNext())
                break;
            Element element4 = (Element)iterator3.next();
            String s1 = element4.getAttributeValue("id");
            boolean flag = false;
            if(hashmap != null)
            {
                Automaton automaton = (Automaton)hashmap.get(s1);
                if(automaton != null)
                {
                    hashmap1.put(s1, automaton);
                    flag = true;
                }
            }
            if(!flag)
                hashmap1.put(s1, makeAutomaton((Element)element4.getChildren().iterator().next()));
        } while(true);
        Node node1;
        StringEdge stringedge;
        for(Iterator iterator4 = element.getChildren("stringedge", namespace).iterator(); iterator4.hasNext(); node1.addStringEdge(stringedge))
        {
            Element element5 = (Element)iterator4.next();
            node1 = lookupNode(element5.getAttributeValue("src"));
            String s3 = element5.getAttributeValue("gap");
            HashSet hashset1 = new HashSet();
            Element element9;
            for(Iterator iterator9 = element5.getChildren("origin", namespace).iterator(); iterator9.hasNext(); hashset1.add(element9.getText()))
                element9 = (Element)iterator9.next();

            if(hashset1.isEmpty())
                hashset1.add("?");
            stringedge = new StringEdge(s3, hashset1);
            stringedge.addLabels((Automaton)hashmap1.get(element5.getAttributeValue("reg")));
        }

        for(Iterator iterator5 = element.getChildren("gappresence", namespace).iterator(); iterator5.hasNext();)
        {
            Element element6 = (Element)iterator5.next();
            String s2 = element6.getAttributeValue("gap");
            Iterator iterator7 = element6.getChildren().iterator();
            while(iterator7.hasNext())
            {
                Element element7 = (Element)iterator7.next();
                if(element7.getName().equals("open"))
                {
                    Node node4 = lookupNode(element7.getAttributeValue("node"));
                    node4.addOpenGap(s2);
                } else
                if(element7.getName().equals("template"))
                {
                    String s5 = element7.getAttributeValue("open");
                    if(s5 != null && s5.equals("yes"))
                        addOpenTemplateGap(s2);
                    String s7 = element7.getAttributeValue("closed");
                    if(s7 != null && s7.equals("yes"))
                        addClosedTemplateGap(s2);
                } else
                if(element7.getName().equals("attribute"))
                {
                    String s6 = element7.getAttributeValue("open");
                    if(s6 != null && s6.equals("yes"))
                        addOpenAttributeGap(s2);
                    String s8 = element7.getAttributeValue("closed");
                    if(s8 != null && s8.equals("yes"))
                        addClosedAttributeGap(s2);
                }
            }
        }

    }

    public Object clone()
    {
        Graph graph = new Graph();
        Node node2;
        for(Iterator iterator = nodes.values().iterator(); iterator.hasNext(); graph.addNode(node2))
        {
            Node node = (Node)iterator.next();
            node2 = (Node)node.clone();
        }

        for(Iterator iterator1 = nodes.values().iterator(); iterator1.hasNext();)
        {
            Node node1 = (Node)iterator1.next();
            Node node3 = graph.lookupNode(node1.key);
            node3.template_edges = node1.cloneTemplateEdges(graph.nodes);
            node3.string_edges = node1.cloneStringEdges();
        }

        for(Iterator iterator2 = roots.values().iterator(); iterator2.hasNext(); graph.addRoot((Node)iterator2.next()));
        graph.tgaps_open = (HashSet)tgaps_open.clone();
        graph.tgaps_closed = (HashSet)tgaps_closed.clone();
        graph.agaps_open = (HashSet)agaps_open.clone();
        graph.agaps_closed = (HashSet)agaps_closed.clone();
        return graph;
    }

    public void addNode(Node node)
    {
        nodes.put(node.key, node);
    }

    public void addRoot(Node node)
    {
        roots.put(node.key, node);
    }

    public Collection getNodes()
    {
        return nodes.values();
    }

    public Collection getRoots()
    {
        return roots.values();
    }

    public Node lookupNode(Object obj)
    {
        return (Node)nodes.get(obj);
    }

    public HashSet getOpenTemplateGaps()
    {
        return tgaps_open;
    }

    public boolean addOpenTemplateGap(String s)
    {
        return tgaps_open.add(s);
    }

    public boolean removeOpenTemplateGap(String s)
    {
        return tgaps_open.remove(s);
    }

    public HashSet getOpenAttributeGaps()
    {
        return agaps_open;
    }

    public boolean addOpenAttributeGap(String s)
    {
        return agaps_open.add(s);
    }

    public boolean removeOpenAttributeGap(String s)
    {
        return agaps_open.remove(s);
    }

    public HashSet getClosedTemplateGaps()
    {
        return tgaps_closed;
    }

    public boolean addClosedTemplateGap(String s)
    {
        return tgaps_closed.add(s);
    }

    public boolean removeClosedTemplateGap(String s)
    {
        return tgaps_closed.remove(s);
    }

    public HashSet getClosedAttributeGaps()
    {
        return agaps_closed;
    }

    public boolean addClosedAttributeGap(String s)
    {
        return agaps_closed.add(s);
    }

    public boolean removeClosedAttributeGap(String s)
    {
        return agaps_closed.remove(s);
    }

    public Document toXML(String s)
    {
        Element element = new Element("summarygraph", sg_namespace);
        Document document = new Document(element);
        automata = new HashMap();
        automata2 = new HashMap();
        for(Iterator iterator = nodes.values().iterator(); iterator.hasNext();)
        {
            Node node = (Node)iterator.next();
            Iterator iterator2 = node.string_edges.values().iterator();
            while(iterator2.hasNext())
            {
                StringEdge stringedge = (StringEdge)iterator2.next();
                Automaton automaton = stringedge.getLabels();
                if(!automata.containsKey(automaton))
                {
                    String s3 = "A" + (automata.size() + 1);
                    automata.put(automaton, s3);
                    Element element5 = new Element("regdef", sg_namespace);
                    element5.setAttribute("id", s3);
                    if(automaton.isTotal())
                    {
                        Element element6 = new Element("string", sg_namespace);
                        element5.addContent(element6);
                    } else
                    {
                        Element element7 = new Element("automaton", sg_namespace);
                        element7.setAttribute("href", s + s3 + ".aut");
                        automata2.put(s3 + ".aut", automaton);
                        element5.addContent(element7);
                    }
                    element.addContent(element5);
                }
            }
        }

        for(Iterator iterator1 = nodes.values().iterator(); iterator1.hasNext();)
        {
            Node node1 = (Node)iterator1.next();
            String s1 = node1.key.toString();
            Element element1 = new Element("node", sg_namespace);
            element1.setAttribute("id", s1);
            Iterator iterator4 = node1.getTemplate().xml.iterator();
            do
            {
                if(!iterator4.hasNext())
                    break;
                Object obj = iterator4.next();
                if(obj instanceof Text)
                    element1.addContent((Text)((Text)obj).clone());
                else
                if(obj instanceof Element)
                    element1.addContent((Element)((Element)obj).clone());
                else
                if(obj instanceof Comment)
                    element1.addContent((Comment)((Comment)obj).clone());
                else
                if(obj instanceof ProcessingInstruction)
                    element1.addContent((ProcessingInstruction)((ProcessingInstruction)obj).clone());
                else
                if(obj instanceof CDATA)
                    element1.addContent((CDATA)((CDATA)obj).clone());
                else
                if(obj instanceof EntityRef)
                    element1.addContent((EntityRef)((EntityRef)obj).clone());
            } while(true);
            element.addContent(element1);
            if(roots.containsKey(node1.key))
                element.addContent((new Element("root", sg_namespace)).setAttribute("node", s1));
            Element element8;
            for(Iterator iterator5 = node1.template_edges.values().iterator(); iterator5.hasNext(); element.addContent(element8))
            {
                TemplateEdge templateedge = (TemplateEdge)iterator5.next();
                element8 = new Element("templateedge", sg_namespace);
                element8.setAttribute("src", s1);
                element8.setAttribute("gap", templateedge.gap);
                element8.setAttribute("dest", templateedge.to.key.toString());
            }

            Element element9;
            for(Iterator iterator6 = node1.string_edges.values().iterator(); iterator6.hasNext(); element.addContent(element9))
            {
                StringEdge stringedge1 = (StringEdge)iterator6.next();
                element9 = new Element("stringedge", sg_namespace);
                element9.setAttribute("src", s1);
                element9.setAttribute("gap", stringedge1.gap);
                element9.setAttribute("reg", (String)automata.get(stringedge1.getLabels()));
            }

            Iterator iterator7 = node1.getOpenGaps().iterator();
            while(iterator7.hasNext())
            {
                String s4 = (String)iterator7.next();
                Element element10 = new Element("gappresence", sg_namespace);
                element10.setAttribute("gap", s4);
                element10.addContent((new Element("open", sg_namespace)).setAttribute("node", s1));
                element.addContent(element10);
            }
        }

        HashSet hashset = new HashSet();
        hashset.addAll(tgaps_open);
        hashset.addAll(tgaps_closed);
        hashset.addAll(agaps_open);
        hashset.addAll(agaps_closed);
        Iterator iterator3 = hashset.iterator();
        do
        {
            if(!iterator3.hasNext())
                break;
            String s2 = (String)iterator3.next();
            if(tgaps_open.contains(s2) || agaps_open.contains(s2))
            {
                Element element2 = new Element("gappresence", sg_namespace);
                element2.setAttribute("gap", s2);
                if(tgaps_open.contains(s2))
                {
                    Element element3 = new Element("template", sg_namespace);
                    element3.setAttribute("open", "yes");
                    if(tgaps_closed.contains(s2))
                        element3.setAttribute("closed", "yes");
                    element2.addContent(element3);
                }
                if(agaps_open.contains(s2))
                {
                    Element element4 = new Element("attribute", sg_namespace);
                    element4.setAttribute("open", "yes");
                    if(agaps_closed.contains(s2))
                        element4.setAttribute("closed", "yes");
                    element2.addContent(element4);
                }
                element.addContent(element2);
            }
        } while(true);
        return document;
    }

    public Map getAutomata()
    {
        return automata2;
    }

    public String toDot()
    {
        int i = 0;
        StringBuffer stringbuffer = new StringBuffer("digraph SummaryGraph {\n");
        stringbuffer.append("  rankdir = LR;\n");
        for(Iterator iterator = nodes.values().iterator(); iterator.hasNext();)
        {
            Node node = (Node)iterator.next();
            stringbuffer.append("  ").append(node);
            stringbuffer.append(" [shape=circle,label=\"" + node.getOrigin() + "\"];\n");
            if(roots.containsKey(node.key))
            {
                stringbuffer.append("  initial [shape=plaintext,label=\"\"];\n");
                stringbuffer.append("  initial -> ").append(node).append("\n");
            }
            TemplateEdge templateedge;
            for(Iterator iterator1 = node.template_edges.values().iterator(); iterator1.hasNext(); stringbuffer.append(" [label=\"").append(templateedge.gap).append("\"]\n"))
            {
                templateedge = (TemplateEdge)iterator1.next();
                stringbuffer.append("  ").append(node).append(" -> ").append(templateedge.to);
            }

            for(Iterator iterator3 = node.string_edges.values().iterator(); iterator3.hasNext();)
            {
                StringEdge stringedge = (StringEdge)iterator3.next();
                stringbuffer.append("  ").append("s" + i).append(" [shape=box,label=\"");
                Automaton automaton = stringedge.labels;
                if(automaton.isFinite())
                {
                    Iterator iterator5 = automaton.getFiniteStrings().iterator();
                    do
                    {
                        if(!iterator5.hasNext())
                            break;
                        stringbuffer.append(dotEscape((String)iterator5.next()));
                        if(iterator5.hasNext())
                            stringbuffer.append(",");
                    } while(true);
                } else
                {
                    Object obj = automaton.getInfo();
                    if(obj != null)
                        stringbuffer.append(obj);
                    else
                        stringbuffer.append("[infinite]");
                }
                stringbuffer.append("\"];\n");
                stringbuffer.append("  ").append(node).append(" -> ").append("s" + i);
                stringbuffer.append(" [label=\"").append(stringedge.gap).append("\"]\n");
                i++;
            }

            Iterator iterator4 = node.open_gaps.iterator();
            while(iterator4.hasNext())
            {
                stringbuffer.append("  ").append("p" + i).append(" [shape=plaintext,label=\"O\"];\n");
                stringbuffer.append("  ").append(node).append(" -> ").append("p" + i);
                stringbuffer.append(" [style=dashed,dir=none,label=\"").append(iterator4.next()).append("\"]\n");
                i++;
            }
        }

        stringbuffer.append("  gp [shape=plaintext,label=\"");
        HashSet hashset = new HashSet();
        hashset.addAll(tgaps_open);
        hashset.addAll(tgaps_closed);
        hashset.addAll(agaps_open);
        hashset.addAll(agaps_closed);
        Iterator iterator2 = hashset.iterator();
        do
        {
            if(!iterator2.hasNext())
                break;
            String s = (String)iterator2.next();
            if(tgaps_open.contains(s) || agaps_open.contains(s))
            {
                stringbuffer.append(s + ": ");
                if(tgaps_open.contains(s))
                {
                    stringbuffer.append("T");
                    if(tgaps_closed.contains(s))
                        stringbuffer.append("?");
                }
                if(agaps_open.contains(s))
                {
                    stringbuffer.append("A");
                    if(agaps_closed.contains(s))
                        stringbuffer.append("?");
                }
                stringbuffer.append("\\n");
            }
        } while(true);
        stringbuffer.append("\"];\n");
        return stringbuffer.append("}\n").toString();
    }

    private String dotEscape(String s)
    {
        StringBuffer stringbuffer = new StringBuffer();
        for(int i = 0; i < s.length(); i++)
        {
            char c = s.charAt(i);
            if(c >= ' ' && c <= '~')
            {
                stringbuffer.append(c);
                continue;
            }
            stringbuffer.append("\\\\u");
            String s1 = Integer.toHexString(c & 0xffff);
            for(int j = 0; j + s1.length() < 4; j++)
                stringbuffer.append('0');

            stringbuffer.append(s1);
        }

        return stringbuffer.toString();
    }

    public void setReverseEdges()
    {
        if(reverse_edges_set)
            return;
        for(Iterator iterator = nodes.values().iterator(); iterator.hasNext();)
        {
            Node node = (Node)iterator.next();
            node.reverse_edges = new HashSet();
        }

        Node node1;
        for(Iterator iterator1 = nodes.values().iterator(); iterator1.hasNext(); setReverseEdges(node1, node1.xml.getXML()))
            node1 = (Node)iterator1.next();

        reverse_edges_set = true;
    }

    private void setReverseEdges(Node node, List list)
    {
        Iterator iterator = list.iterator();
        do
        {
            if(!iterator.hasNext())
                break;
            Object obj = iterator.next();
            if(obj instanceof Element)
            {
                Element element = (Element)obj;
                if(Template.isGap(element))
                {
                    String s = Template.getGap(element);
                    Iterator iterator1 = node.lookupTemplateEdges(s).iterator();
                    while(iterator1.hasNext())
                    {
                        TemplateEdge templateedge = (TemplateEdge)iterator1.next();
                        templateedge.getDestination().reverse_edges.add(new Location(node, element));
                    }
                } else
                {
                    setReverseEdges(node, element.getContent());
                }
            }
        } while(true);
    }

    private Automaton makeAutomaton(Element element)
        throws IOException, OptionalDataException, ClassCastException, ClassNotFoundException, InvalidClassException
    {
        Automaton automaton = null;
        if(element.getName().equals("automaton"))
        {
            File file = new File(System.getProperty("user.dir"));
            automaton = Automaton.load(new URL(file.toURL(), element.getAttributeValue("href")));
        } else
        if(element.getName().equals("sequence"))
        {
            Iterator iterator = element.getChildren().iterator();
            if(!iterator.hasNext())
                return Automaton.makeEmptyString();
            while(iterator.hasNext())
            {
                Automaton automaton1 = makeAutomaton((Element)iterator.next());
                if(automaton == null)
                    automaton = automaton1;
                else
                    automaton = automaton.concatenate(automaton1);
            }
            automaton.minimize();
        } else
        {
            if(element.getName().equals("optional"))
                return makeAutomaton((Element)element.getChildren().iterator().next()).optional();
            if(element.getName().equals("complement"))
                return makeAutomaton((Element)element.getChildren().iterator().next()).complement();
            if(element.getName().equals("union"))
            {
                Iterator iterator1 = element.getChildren().iterator();
                if(!iterator1.hasNext())
                    return Automaton.makeEmpty();
                while(iterator1.hasNext())
                {
                    Automaton automaton2 = makeAutomaton((Element)iterator1.next());
                    if(automaton == null)
                        automaton = automaton2;
                    else
                        automaton = automaton.union(automaton2);
                }
                automaton.minimize();
            } else
            if(element.getName().equals("intersection"))
            {
                Iterator iterator2 = element.getChildren().iterator();
                if(!iterator2.hasNext())
                    return Automaton.makeAnyString();
                while(iterator2.hasNext())
                {
                    Automaton automaton3 = makeAutomaton((Element)iterator2.next());
                    if(automaton == null)
                        automaton = automaton3;
                    else
                        automaton = automaton.intersection(automaton3);
                }
                automaton.minimize();
            } else
            if(element.getName().equals("minus"))
            {
                Iterator iterator3 = element.getChildren().iterator();
                Automaton automaton4 = makeAutomaton((Element)iterator3.next());
                Automaton automaton5 = makeAutomaton((Element)iterator3.next());
                automaton = automaton4.intersection(automaton5.complement());
                automaton.minimize();
            } else
            if(element.getName().equals("repeat"))
            {
                automaton = makeAutomaton((Element)element.getChildren().iterator().next());
                String s = element.getAttributeValue("number");
                String s3 = element.getAttributeValue("min");
                String s5 = element.getAttributeValue("max");
                if(s != null)
                    automaton = automaton.repeat(Integer.parseInt(s), Integer.parseInt(s));
                else
                if(s3 == null && s5 == null)
                    automaton = automaton.repeat();
                else
                if(s3 != null && s5 != null)
                    automaton = automaton.repeat(Integer.parseInt(s3), Integer.parseInt(s5));
                else
                if(s3 == null && s5 != null)
                    automaton = automaton.repeat(0, Integer.parseInt(s5));
                else
                    automaton = automaton.repeat(Integer.parseInt(s3));
                automaton.minimize();
            } else
            if(element.getName().equals("string"))
            {
                String s1 = element.getAttributeValue("value");
                if(s1 == null)
                    automaton = Automaton.makeAnyString();
                else
                    automaton = Automaton.makeString(s1);
            } else
            if(element.getName().equals("char"))
            {
                String s2 = element.getAttributeValue("set");
                String s4 = element.getAttributeValue("min");
                String s6 = element.getAttributeValue("max");
                if(s2 == null && s4 == null && s6 == null)
                    return Automaton.makeAnyChar();
                if(s2 != null)
                    automaton = Automaton.makeCharSet(s2);
                else
                if(s4 == null && s6 != null)
                    automaton = Automaton.makeCharRange('\0', s6.charAt(0));
                else
                if(s4 != null && s6 == null)
                    automaton = Automaton.makeCharRange(s4.charAt(0), '\uFFFF');
                else
                    automaton = Automaton.makeCharRange(s4.charAt(0), s6.charAt(0));
            }
        }
        return automaton;
    }

    HashMap nodes;
    HashMap roots;
    HashSet tgaps_open;
    HashSet tgaps_closed;
    HashSet agaps_open;
    HashSet agaps_closed;
    private boolean reverse_edges_set;
    static String sg_namespace = "http://www.brics.dk/summarygraph";
    HashMap automata;
    HashMap automata2;

}

